﻿using DualPlaneFR4Paster.Common.Services;
using DualPlaneFR4Paster.Extensions;
using DualPlaneFR4Paster.Models;
using DualPlaneFR4Paster.Views.Dialogs;
using HalconDotNet;
using Microsoft.EntityFrameworkCore.Storage.Internal;
using NLog;
using Prism.Commands;
using Prism.Events;
using Prism.Ioc;
using Prism.Mvvm;
using Prism.Regions;
using Prism.Services.Dialogs;
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace DualPlaneFR4Paster.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {
        #region 变量
        private ICameraService cam1, cam2, cam3, cam4;
        private readonly IRegionManager regionManager;
        private readonly IDialogService dialogService;
        private readonly IDialogHostService _dialogHostService;
        private IParamService paramService;
        bool IsTopFloorAxisDialogShow = false, IsBottomFloorAxisDialogShow = false, IsPLCDialogShow = false, IsFeederDialogShow = false, IsPastePointDialogShow = false, IsPartNumDialogShow = false,
            IsCameraFilmCalibDialog = false, IsParameterDialogShow = false, IsAlarmDialogShow = false;
        private static Logger logger = LogManager.GetCurrentClassLogger();
        private IServoModbusService servoModbus;
        private IPLCModbusService plcModbus;
        private IStepMotorModbusService stepMotorModbus;
        private IGTSCardService Top_A8;
        private IGTSCardService Top_A4;
        private IGTSCardService Bottom_A8;
        private CancellationTokenSource source;
        public readonly IEventAggregator aggregator;
        #endregion
        #region 属性
        private string title;
        public string Title
        {
            get { return title; }
            set { SetProperty(ref title, value); }
        }
        private string version;
        public string Version
        {
            get { return version; }
            set { SetProperty(ref version, value); }
        }
        private string partName;
        public string PartName
        {
            get { return partName; }
            set { SetProperty(ref partName, value); }
        }
        private string topFloorVisibility;
        public string TopFloorVisibility
        {
            get { return topFloorVisibility; }
            set { SetProperty(ref topFloorVisibility, value); }
        }
        private string bottomFloorVisibility;
        public string BottomFloorVisibility
        {
            get { return bottomFloorVisibility; }
            set { SetProperty(ref bottomFloorVisibility, value); }
        }
        private bool pLCState;
        public bool PLCState
        {
            get { return pLCState; }
            set { SetProperty(ref pLCState, value); }
        }
        private bool topDownCameraState;
        public bool TopDownCameraState
        {
            get { return topDownCameraState; }
            set { SetProperty(ref topDownCameraState, value); }
        }
        private bool topUpCameraState;
        public bool TopUpCameraState
        {
            get { return topUpCameraState; }
            set { SetProperty(ref topUpCameraState, value); }
        }
        private bool bottomDownCameraState;
        public bool BottomDownCameraState
        {
            get { return bottomDownCameraState; }
            set { SetProperty(ref bottomDownCameraState, value); }
        }
        private bool bottomUpCameraState;
        public bool BottomUpCameraState
        {
            get { return bottomUpCameraState; }
            set { SetProperty(ref bottomUpCameraState, value); }
        }
        private bool servoState;
        public bool ServoState
        {
            get { return servoState; }
            set { SetProperty(ref servoState, value); }
        }
        private bool topA8AxisCardState;
        public bool TopA8AxisCardState
        {
            get { return topA8AxisCardState; }
            set { SetProperty(ref topA8AxisCardState, value); }
        }
        private bool bottomA8AxisCardState;
        public bool BottomA8AxisCardState
        {
            get { return bottomA8AxisCardState; }
            set { SetProperty(ref bottomA8AxisCardState, value); }
        }
        private bool a4AxisCardState;
        public bool A4AxisCardState
        {
            get { return a4AxisCardState; }
            set { SetProperty(ref a4AxisCardState, value); }
        }
        private bool stepMotorState;
        public bool StepMotorState
        {
            get { return stepMotorState; }
            set { SetProperty(ref stepMotorState, value); }
        }
        #endregion
        #region 命令
        private DelegateCommand appLoadedEventCommand;
        public DelegateCommand AppLoadedEventCommand =>
            appLoadedEventCommand ?? (appLoadedEventCommand = new DelegateCommand(ExecuteAppLoadedEventCommand));
        private DelegateCommand appClosedEventCommand;
        public DelegateCommand AppClosedEventCommand =>
            appClosedEventCommand ?? (appClosedEventCommand = new DelegateCommand(ExecuteAppClosedEventCommand));
        private DelegateCommand<object> menuCommand;
        public DelegateCommand<object> MenuCommand =>
            menuCommand ?? (menuCommand = new DelegateCommand<object>(ExecuteMenuCommand));
        int index1 = 0;
        void ExecuteMenuCommand(object obj)
        {
            switch (obj.ToString())
            {
                case "卷料":
                    if (!IsFeederDialogShow)
                    {
                        var result = _dialogHostService.Password("请输入密码");
                        if (result == ButtonResult.Yes)
                        {
                            IsFeederDialogShow = true;
                            DialogParameters param = new DialogParameters();
                            param.Add("PartNum", paramService.GetPart());
                            dialogService.Show("FeederDialog", param, arg =>
                            {
                                IsFeederDialogShow = false;
                            });
                        }
                    }
                    break;
                case "贴合点":
                    if (!IsPastePointDialogShow)
                    {
                        var result = _dialogHostService.Password("请输入密码");
                        if (result == ButtonResult.Yes)
                        {
                            IsPastePointDialogShow = true;
                            DialogParameters param = new DialogParameters();
                            param.Add("PartNum", paramService.GetPart());
                            dialogService.Show("PastePointDialog", param, arg =>
                            {
                                IsPastePointDialogShow = false;
                            });
                        }
                    }
                    break;
                case "参数":
                    if (!IsParameterDialogShow)
                    {
                        var result = _dialogHostService.Password("请输入密码");
                        if (result == ButtonResult.Yes)
                        {
                            IsParameterDialogShow = true;
                            DialogParameters param = new DialogParameters();
                            param.Add("PartNum", paramService.GetPart());
                            dialogService.Show("ParameterDialog", param, arg =>
                            {
                                IsParameterDialogShow = false;
                            });
                        }
                    }
                    break;
                case "上层轴":
                    if (!IsTopFloorAxisDialogShow)
                    {
                        var result = _dialogHostService.Password("请输入密码");
                        if (result == ButtonResult.Yes)
                        {
                            IsTopFloorAxisDialogShow = true;
                            DialogParameters param = new DialogParameters();
                            param.Add("PartNum", paramService.GetPart());
                            dialogService.Show("TopFloorAxisDialog", param, arg =>
                            {
                                IsTopFloorAxisDialogShow = false;
                            });
                        }
                    }
                    break;
                case "下层轴":
                    if (!IsBottomFloorAxisDialogShow)
                    {
                        var result = _dialogHostService.Password("请输入密码");
                        if (result == ButtonResult.Yes)
                        {
                            IsBottomFloorAxisDialogShow = true;
                            DialogParameters param = new DialogParameters();
                            param.Add("PartNum", paramService.GetPart());
                            dialogService.Show("BottomFloorAxisDialog", param, arg =>
                            {
                                IsBottomFloorAxisDialogShow = false;
                            });
                        }
                    }
                    break;
                case "PLC":
                    if (!IsPLCDialogShow)
                    {
                        var result = _dialogHostService.Password("请输入密码");
                        if (result == ButtonResult.Yes)
                        {
                            IsPLCDialogShow = true;
                            DialogParameters param = new DialogParameters();
                            param.Add("PartNum", paramService.GetPart());
                            dialogService.Show("PLCDialog", param, arg =>
                            {
                                IsPLCDialogShow = false;
                            });
                        }
                    }
                    break;
                case "料号":
                    if (!IsPartNumDialogShow)
                    {
                        var result = _dialogHostService.Password("请输入密码");
                        if (result == ButtonResult.Yes)
                        {
                            IsPartNumDialogShow = true;
                            dialogService.Show("PartNumDialog", arg =>
                            {
                                IsPartNumDialogShow = false;
                            });
                        }
                    }
                    break;
                case "视觉上层-膜标定":
                    if (!IsCameraFilmCalibDialog)
                    {
                        var result = _dialogHostService.Password("请输入密码");
                        if (result == ButtonResult.Yes)
                        {
                            IsCameraFilmCalibDialog = true;
                            DialogParameters param = new DialogParameters();
                            param.Add("PartNum", paramService.GetPart());
                            param.Add("Floor", 1);
                            dialogService.Show("CameraFilmCalibDialog", param, arg =>
                            {
                                IsCameraFilmCalibDialog = false;
                            });
                        }
                    }
                    break;
                case "视觉上层-产品标定":
                    if (!IsCameraFilmCalibDialog)
                    {
                        var result = _dialogHostService.Password("请输入密码");
                        if (result == ButtonResult.Yes)
                        {
                            IsCameraFilmCalibDialog = true;
                            DialogParameters param = new DialogParameters();
                            param.Add("PartNum", paramService.GetPart());
                            param.Add("Floor", 1);
                            dialogService.Show("CameraProductCalibDialog", param, arg =>
                            {
                                IsCameraFilmCalibDialog = false;
                            });
                        }
                    }
                    break;
                case "视觉下层-膜标定":
                    if (!IsCameraFilmCalibDialog)
                    {
                        var result = _dialogHostService.Password("请输入密码");
                        if (result == ButtonResult.Yes)
                        {
                            IsCameraFilmCalibDialog = true;
                            DialogParameters param = new DialogParameters();
                            param.Add("PartNum", paramService.GetPart());
                            param.Add("Floor", 2);
                            dialogService.Show("CameraFilmCalibDialog", param, arg =>
                            {
                                IsCameraFilmCalibDialog = false;
                            });
                        }
                    }
                    break;
                case "视觉下层-产品标定":
                    if (!IsCameraFilmCalibDialog)
                    {
                        var result = _dialogHostService.Password("请输入密码");
                        if (result == ButtonResult.Yes)
                        {
                            IsCameraFilmCalibDialog = true;
                            DialogParameters param = new DialogParameters();
                            param.Add("PartNum", paramService.GetPart());
                            param.Add("Floor", 2);
                            dialogService.Show("CameraProductCalibDialog", param, arg =>
                            {
                                IsCameraFilmCalibDialog = false;
                            });
                        }
                    }
                    break;
                case "视觉上层-膜算法":
                    if (!IsCameraFilmCalibDialog)
                    {
                        var result = _dialogHostService.Password("请输入密码");
                        if (result == ButtonResult.Yes)
                        {
                            IsCameraFilmCalibDialog = true;
                            DialogParameters param = new DialogParameters();
                            param.Add("PartNum", paramService.GetPart());
                            param.Add("Floor", 1);
                            dialogService.Show("CameraFilmVisionCalcDialog", param, arg =>
                            {
                                IsCameraFilmCalibDialog = false;
                            });
                        }
                    }
                    break;
                case "视觉下层-膜算法":
                    if (!IsCameraFilmCalibDialog)
                    {
                        var result = _dialogHostService.Password("请输入密码");
                        if (result == ButtonResult.Yes)
                        {
                            IsCameraFilmCalibDialog = true;
                            DialogParameters param = new DialogParameters();
                            param.Add("PartNum", paramService.GetPart());
                            param.Add("Floor", 2);
                            dialogService.Show("CameraFilmVisionCalcDialog", param, arg =>
                            {
                                IsCameraFilmCalibDialog = false;
                            });
                        }
                    }
                    break;
                case "视觉上层-产品算法":
                    if (!IsCameraFilmCalibDialog)
                    {
                        var result = _dialogHostService.Password("请输入密码");
                        if (result == ButtonResult.Yes)
                        {
                            IsCameraFilmCalibDialog = true;
                            DialogParameters param = new DialogParameters();
                            param.Add("PartNum", paramService.GetPart());
                            param.Add("Floor", 1);
                            dialogService.Show("CameraProductVisionCalcDialog", param, arg =>
                            {
                                IsCameraFilmCalibDialog = false;
                            });
                        }
                    }
                    break;
                case "视觉下层-产品算法":
                    if (!IsCameraFilmCalibDialog)
                    {
                        var result = _dialogHostService.Password("请输入密码");
                        if (result == ButtonResult.Yes)
                        {
                            IsCameraFilmCalibDialog = true;
                            DialogParameters param = new DialogParameters();
                            param.Add("PartNum", paramService.GetPart());
                            param.Add("Floor", 2);
                            dialogService.Show("CameraProductVisionCalcDialog", param, arg =>
                            {
                                IsCameraFilmCalibDialog = false;
                            });
                        }
                    }
                    break;
                case "关于":
                    {
                        DialogParameters param = new DialogParameters();
                        param.Add("Name", Title);
                        param.Add("Version", Version);
                        dialogService.ShowDialog("AboutDialog", param, arg => { });
                    }
                    break;
                case "显示上层":
                    {
                        TopFloorVisibility = "Visible";
                        BottomFloorVisibility = "Collapsed";
                    }
                    break;
                case "显示下层":
                    {
                        TopFloorVisibility = "Collapsed";
                        BottomFloorVisibility = "Visible";
                    }
                    break;
                default:
                    break;
            }
        }
        async void ExecuteAppClosedEventCommand()
        {
            aggregator.SendMessage("AppClose");
            GTSCard.AxisStop(Top_A8.A1, 1);
            GTSCard.AxisStop(Top_A8.A2, 1);
            GTSCard.AxisStop(Top_A8.A4, 1);
            GTSCard.AxisStop(Top_A8.A5, 1);
            GTSCard.AxisStop(Top_A8.A6, 1);
            GTSCard.AxisStop(Top_A8.A7, 1);
            GTSCard.AxisStop(Top_A4.A1, 1);
            GTSCard.AxisStop(Top_A4.A2, 1);
            GTSCard.AxisStop(Bottom_A8.A1, 1);
            GTSCard.AxisStop(Bottom_A8.A2, 1);
            GTSCard.AxisStop(Bottom_A8.A4, 1);
            GTSCard.AxisStop(Bottom_A8.A5, 1);
            GTSCard.AxisStop(Bottom_A8.A6, 1);
            GTSCard.AxisStop(Bottom_A8.A7, 1);
            GTSCard.AxisStop(Top_A4.A3, 1);
            GTSCard.AxisStop(Top_A4.A4, 1);
            GTSCard.ServoOff(Top_A8.A1);
            GTSCard.ServoOff(Top_A8.A2);
            GTSCard.ServoOff(Top_A8.A4);
            GTSCard.ServoOff(Top_A8.A5);
            GTSCard.ServoOff(Top_A8.A6);
            GTSCard.ServoOff(Top_A8.A7);
            GTSCard.ServoOff(Top_A4.A1);
            GTSCard.ServoOff(Top_A4.A2);
            GTSCard.ServoOff(Bottom_A8.A1);
            GTSCard.ServoOff(Bottom_A8.A2);
            GTSCard.ServoOff(Bottom_A8.A4);
            GTSCard.ServoOff(Bottom_A8.A5);
            GTSCard.ServoOff(Bottom_A8.A6);
            GTSCard.ServoOff(Bottom_A8.A7);
            GTSCard.ServoOff(Top_A4.A3);
            GTSCard.ServoOff(Top_A4.A4);
            GTSCard.SetDoPort1(Top_A8.A1.CardNo, 0xFFFF);
            GTSCard.SetDoPort1(Bottom_A8.A1.CardNo, 0xFFFF);
            GTSCard.SetDoPort1(Top_A4.A1.CardNo, 0xFFFF);

            cam1.CloseCamera();
            cam2.CloseCamera();
            cam3.CloseCamera();
            cam4.CloseCamera();
            servoModbus.Close();
            if (source != null)
            {
                source.Cancel();
            }
            await Task.Delay(200);
            plcModbus.Close();
        }
        void ExecuteAppLoadedEventCommand()
        {
            string servoCom = string.Empty, plcCom = string.Empty,stepMotorCom = string.Empty;
            using (var sysDb = new SysContext())
            {
                var com = sysDb.MSystemParams.FirstOrDefault(p => p.Name == "ServoCOM");
                if (com != null)
                {
                    servoCom = com.Value.ToString();
                }
                com = sysDb.MSystemParams.FirstOrDefault(p => p.Name == "PLCCOM");
                if (com != null)
                {
                    plcCom = com.Value.ToString();
                }
                com = sysDb.MSystemParams.FirstOrDefault(p => p.Name == "StepMotorCOM");
                if (com != null)
                {
                    stepMotorCom = com.Value.ToString();
                }
            }
            bool servoInit = false, plcInit = false, stepMotorInit = false;
            if (servoCom != string.Empty)
            {
                ServoState = servoInit = servoModbus.Connect(servoCom);
            }
            if (plcCom != string.Empty)
            {
                PLCState = plcInit = plcModbus.Connect(plcCom);
            }
            if (stepMotorCom != string.Empty)
            {
                StepMotorState = stepMotorInit = stepMotorModbus.Connect(stepMotorCom);
            }
            if (servoInit && plcInit && stepMotorInit)
            {
                regionManager.Regions["TopFloorRegion"].RequestNavigate("TopFloor");
                regionManager.Regions["BottomFloorRegion"].RequestNavigate("BottomFloor");
                logger.Info("软件加载完成");
                source = new CancellationTokenSource();
                CancellationToken token = source.Token;
                Task.Run(() => PLCReadAction(token), token);
            }
            else
            {
                if (!servoInit)
                {
                    _dialogHostService.MessageBox(MessageType.Message, "信息", "伺服串口连接失败");
                    logger.Info("伺服串口连接失败");
                }
                if (!plcInit)
                {
                    _dialogHostService.MessageBox(MessageType.Message, "信息", "PLC串口连接失败");
                    logger.Info("PLC串口连接失败");
                }
                if (!stepMotorInit)
                {
                    _dialogHostService.MessageBox(MessageType.Message, "信息", "步进串口连接失败");
                    logger.Info("步进串口连接失败");
                }
            }
            //regionManager.Regions["TopFloorRegion"].RequestNavigate("TopFloor");
            //regionManager.Regions["BottomFloorRegion"].RequestNavigate("BottomFloor");
        }
        #endregion
        public MainWindowViewModel(IRegionManager _regionManager, IContainerProvider containerProvider)
        {
            regionManager = _regionManager;
            dialogService = containerProvider.Resolve<IDialogService>();
            _dialogHostService = containerProvider.Resolve<IDialogHostService>();
            cam1 = containerProvider.Resolve<ICameraService>("Floor1Down");
            cam2 = containerProvider.Resolve<ICameraService>("Floor1Up");
            cam3 = containerProvider.Resolve<ICameraService>("Floor2Down"); 
            cam4 = containerProvider.Resolve<ICameraService>("Floor2Up");
            paramService = containerProvider.Resolve<IParamService>("Param");
            servoModbus = containerProvider.Resolve<IServoModbusService>("ServoModbus");
            plcModbus = containerProvider.Resolve<IPLCModbusService>("PLCModbus");
            stepMotorModbus = containerProvider.Resolve<IStepMotorModbusService>("StepMotorModbus");
            Top_A8 = containerProvider.Resolve<IGTSCardService>("Top_A8");
            Top_A4 = containerProvider.Resolve<IGTSCardService>("Top_A4");
            Bottom_A8 = containerProvider.Resolve<IGTSCardService>("Bottom_A8");
            aggregator = containerProvider.Resolve<IEventAggregator>();
            Title = "DualPlaneFR4Paster";
            Version = "1.3.5";
            PartName = paramService.GetPart();
            TopFloorVisibility = "Visible";
            BottomFloorVisibility = "Collapsed";
            HOperatorSet.ResetObjDb(5000, 5000, 1);
            HOperatorSet.SetSystem("clip_region", "false");
            HOperatorSet.SetSystem("store_empty_region", "true");
            NlogConfig();
            aggregator.ResgiterMessage(arg =>
            {
                switch (arg.Message)
                {
                    case "TopDownCameraOK":
                        TopDownCameraState = true;
                        break;
                    case "TopDownCameraNG":
                        TopDownCameraState = false;
                        break;
                    case "TopUpCameraOK":
                        TopUpCameraState = true;
                        break;
                    case "TopUpCameraNG":
                        TopUpCameraState = false;
                        break;
                    case "BottomDownCameraOK":
                        BottomDownCameraState = true;
                        break;
                    case "BottomDownCameraNG":
                        BottomDownCameraState = false;
                        break;
                    case "BottomUpCameraOK":
                        BottomUpCameraState = true;
                        break;
                    case "BottomUpCameraNG":
                        BottomUpCameraState = false;
                        break;
                    case "TopA8AxisCardOK":
                        TopA8AxisCardState = true;
                        break;
                    case "TopA8AxisCardNG":
                        TopA8AxisCardState = false;
                        break;
                    case "BottomA8AxisCardOK":
                        BottomA8AxisCardState = true;
                        break;
                    case "BottomA8AxisCardNG":
                        BottomA8AxisCardState = false;
                        break;
                    case "A4AxisCardOK":
                        A4AxisCardState = true;
                        break;
                    case "A4AxisCardNG":
                        A4AxisCardState = false;
                        break;
                    default:
                        break;
                }
            }, "Status");
            aggregator.ResgiterMessage(arg =>
            {

                if (!IsAlarmDialogShow)
                {
                    IsAlarmDialogShow = true;
                    System.Windows.Application.Current.Dispatcher.Invoke(new Action(() =>
                    {
                        DialogParameters param = new DialogParameters();
                        param.Add("ContainStr", arg.Message);
                        dialogService.Show("AlarmDialog", param, arg =>
                        {
                            IsAlarmDialogShow = false;
                        });
                    }));
                }
                else
                {
                    aggregator.SendMessage(arg.Message, "UpdateAlarm");
                }
            }, "Alarm");
        }
        private void NlogConfig()
        {
            var config = new NLog.Config.LoggingConfiguration();

            // Targets where to log to: File and Console
            var logfile = new NLog.Targets.FileTarget("logfile") { FileName = "${basedir}/logs/${shortdate}.log", Layout = "${longdate}|${level:uppercase=true}|${message}" };
            var logconsole = new NLog.Targets.ConsoleTarget("logconsole");

            // Rules for mapping loggers to targets            
            config.AddRule(NLog.LogLevel.Info, NLog.LogLevel.Fatal, logconsole);
            config.AddRule(NLog.LogLevel.Debug, NLog.LogLevel.Fatal, logfile);

            // Apply config           
            NLog.LogManager.Configuration = config;            
        }
        private void PLCReadAction(CancellationToken token)
        {
            while (true)
            {
                if (token.IsCancellationRequested)
                {
                    return;
                }
                try
                {
                    var coils = plcModbus.ReadM(1, 0x5000, 36);
                    for (int i = 0; i < 36; i++)
                    {
                        plcModbus.XCoils_X0[i] = coils[i];
                    }
                    coils = plcModbus.ReadM(1, 0x5100, 16);
                    for (int i = 0; i < 16; i++)
                    {
                        plcModbus.XCoils_X10000[i] = coils[i];
                    }
                    coils = plcModbus.ReadM(1, 0x5140, 16);
                    for (int i = 0; i < 16; i++)
                    {
                        plcModbus.XCoils_X10100[i] = coils[i];
                    }
                    coils = plcModbus.ReadM(1, 0x5180, 16);
                    for (int i = 0; i < 16; i++)
                    {
                        plcModbus.XCoils_X10200[i] = coils[i];
                    }
                    coils = plcModbus.ReadM(1, 2000, 36);
                    for (int i = 0; i < 36; i++)
                    {
                        plcModbus.MCoils_M2000[i] = coils[i];
                    }
                }
                catch (System.Exception ex)
                { 

                }

                System.Threading.Thread.Sleep(200);
            }
        }
    }
}
